package com.ning.ems.service.impl;

import com.ning.ems.dao.PackageDao;
import com.ning.ems.dto.PackageAddDto;
import com.ning.ems.dto.PackageListDto;
import com.ning.ems.dto.PackageMyListDto;
import com.ning.ems.entity.Package;
import com.ning.ems.entity.User;
import com.ning.ems.enums.PackageState;
import com.ning.ems.exception.ServiceException;
import com.ning.ems.service.AddressService;
import com.ning.ems.service.PackageService;
import com.ning.ems.service.UserService;
import com.ning.ems.vo.AddressVo;
import com.ning.ems.vo.PackageVo;
import com.ning.ems.vo.TableData;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

import static com.ning.ems.util.Util.mapping;
import static com.ning.ems.util.Util.zeroToNull;

/**
 * @author Ning 242741154@qq.com
 * @date 2020/4/11 14:44
 */
@Service
public class PackageServiceImpl implements PackageService {
    private final PackageDao packageDao;
    private final UserService userService;
    private final AddressService addressService;

    public PackageServiceImpl(PackageDao packageDao, UserService userService, AddressService addressService) {
        this.packageDao = packageDao;
        this.userService = userService;
        this.addressService = addressService;
    }

    static String desc(AddressVo address) {
        return address.getProvince() + address.getExactAddr();
    }

    @Override
    public TableData<PackageVo> pkgList(PackageListDto info) {
        Integer senderProvince = zeroToNull(info.getSenderProvince());
        Integer receiverProvince = zeroToNull(info.getReceiverProvince());
        Integer currState = zeroToNull(info.getCurrState());
        final LocalDateTime startTime = LocalDateTime.of(info.getYear(),
                info.getMonth(), 1, 0, 0);
        final LocalDateTime endTime = startTime.plusMonths(1);
        final int offset = (info.getPage() - 1) * info.getPageSize();

        final List<Package> list = packageDao.list(senderProvince,
                receiverProvince, currState,
                startTime, endTime,
                offset, info.getPageSize());
        final List<PackageVo> data = mapping(list, this::toVo);

        final Integer total = packageDao.listTotal(senderProvince,
                receiverProvince, currState,
                startTime, endTime);
        return new TableData<>(total, data);
    }

    @Override
    public PackageVo get(Integer id) {
        Package pkg = packageDao.get(id);
        return pkg == null ? null : toVo(pkg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Package add(PackageAddDto info) {
        Package pkg = new Package();
        pkg.setDesc(info.getDesc());
        pkg.setWeight(info.getWeight());

        Integer addrId = info.getSenderAddr();
        pkg.setSenderAddr(addrId);
        AddressVo address = addressService.get(addrId);
        pkg.setSender(address.getOwner());

        addrId = info.getReceiverAddr();
        pkg.setReceiverAddr(addrId);
        address = addressService.get(addrId);
        if (address == null) {
            throw new ServiceException("");
        }
        pkg.setReceiver(address.getOwner());

        pkg.setTime(LocalDateTime.now());
        packageDao.add(pkg);
        return pkg;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Integer id) {
        int rtn = packageDao.delete(id);
        return rtn == 1;
    }

    @Override
    public Integer myCnt(Integer user) {
        return packageDao.myListTotal(user,
                null, false, null, null);
    }

    @Override
    public TableData<PackageVo> myList(PackageMyListDto info) {
        Integer currState = zeroToNull(info.getCurrState());
        final LocalDateTime startTime = LocalDateTime.of(info.getYear(),
                info.getMonth(), 1, 0, 0);
        final LocalDateTime endTime = startTime.plusMonths(1);
        final int offset = (info.getPage() - 1) * info.getPageSize();

        List<Package> list = packageDao.myList(info.getId(), currState,
                startTime, endTime, offset, info.getPageSize());
        List<PackageVo> data = mapping(list, this::toVo);

        Integer total = packageDao.myListTotal(info.getId(), currState,
                true, startTime, endTime);
        return new TableData<>(total, data);
    }

    private PackageVo toVo(Package pkg) {
        User sender = userService.get(pkg.getSender());
        String sAddr = desc(addressService.get(pkg.getSenderAddr()));
        User receiver = userService.get(pkg.getReceiver());
        String rAddr = desc(addressService.get(pkg.getReceiverAddr()));
        return new PackageVo(pkg.getId(),
                pkg.getDesc(), pkg.getWeight(),
                sender.getName(), sAddr,
                receiver.getName(), rAddr,
                pkg.getTime(),
                PackageState.descOf(pkg.getCurrState()));
    }
}
